package com.my.house.common.config;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.my.house.common.utils.ThreadLocalHolder;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.Objects;

/**
 * 数据自动填充配置类
 *
 * 填充原理是直接给entity的属性设置值!!!
 * 注解则是指定该属性在对应情况下必有值,如果无值则入库会是null
 * MetaObjectHandler提供的默认方法的策略均为:如果属性有值则不覆盖,如果填充值为null则不填充
 * 字段必须声明TableField注解,属性fill选择对应策略,该声明告知Mybatis-Plus需要预留注入SQL字段
 * 填充处理器MyMetaObjectHandler在 Spring Boot 中需要声明@Component或@Bean注入
 * 要想根据注解FieldFill.xxx和字段名以及字段类型来区分必须使用父类的strictInsertFill或者strictUpdateFill方法
 * 不需要根据任何来区分可以使用父类的fillStrategy方法
 * update(T t,Wrapper updateWrapper)时t不能为空,否则自动填充失效
 * @author yangll
 */
@Component
public class MybatisAutoFillConfig implements MetaObjectHandler {
    private static final String CrB = "createdBy", CrAt="createdAt", UpB="updatedBy", UpAt="updatedAt", DELETED="deleted";
    @Override
    public void insertFill(MetaObject metaObject) {
        LocalDateTime now = LocalDateTime.now();
        Long userId = getLoginUserId();
        //自动字段 填充创建人创建时间
        Object crbValue = getFieldValByName(CrB, metaObject);
        if (metaObject.hasSetter(CrB) && (Objects.isNull(crbValue) || Objects.equals(crbValue, 0))) {
            setFieldValByName(CrB, userId, metaObject);
        }
        Object upbValue = getFieldValByName(UpB, metaObject);
        if (metaObject.hasSetter(UpB) && (Objects.isNull(upbValue) || Objects.equals(upbValue, 0))) {
            setFieldValByName(UpB, userId, metaObject);
        }
        if (metaObject.hasSetter(CrAt) && Objects.isNull(getFieldValByName(CrAt, metaObject))) {
            if (metaObject.getSetterType(CrAt).equals(LocalDateTime.class)) {
                setFieldValByName(CrAt, now, metaObject);
            } else if (metaObject.getSetterType(CrAt).equals(Date.class)) {
                setFieldValByName(CrAt, Date.from(now.atZone(ZoneId.systemDefault()).toInstant()), metaObject);
            }
        }
        if (metaObject.hasSetter(UpAt) && Objects.isNull(getFieldValByName(UpAt, metaObject))) {
            if (metaObject.getSetterType(UpAt).equals(LocalDateTime.class)) {
                setFieldValByName(UpAt, now, metaObject);
            } else if (metaObject.getSetterType(UpAt).equals(Date.class)) {
                setFieldValByName(UpAt, Date.from(now.atZone(ZoneId.systemDefault()).toInstant()), metaObject);
            }
        }

        //自动填充 逻辑删除标识
        if (metaObject.hasSetter(DELETED) && Objects.isNull(getFieldValByName(DELETED, metaObject))) {
            //自动填充逻辑删除标识
            Class<?> deleted = metaObject.getSetterType("deleted");
            if (deleted.equals(Boolean.class)) {
                setFieldValByName("deleted", Boolean.FALSE, metaObject);
            } else if (deleted.getSuperclass().equals(Number.class)) {
                setFieldValByName("deleted", 0, metaObject);
            }
        }
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        LocalDateTime now = LocalDateTime.now();
        Long userId = getLoginUserId();
        Object upbValue = getFieldValByName(UpB, metaObject);
        if (metaObject.hasSetter(UpB) && (Objects.isNull(upbValue) || Objects.equals(upbValue, 0))) {
            setFieldValByName(UpB, userId, metaObject);
        }
        if (metaObject.hasSetter(UpAt) && Objects.isNull(getFieldValByName(UpAt, metaObject))) {
            if (metaObject.getSetterType(UpAt).equals(LocalDateTime.class)) {
                setFieldValByName(UpAt, now, metaObject);
            } else if (metaObject.getSetterType(UpAt).equals(Date.class)) {
                setFieldValByName(UpAt, Date.from(now.atZone(ZoneId.systemDefault()).toInstant()), metaObject);
            }
        }
    }

    private Long getLoginUserId() {
        return ThreadLocalHolder.getUserId();
    }
}
